﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Keepo.Models;
using System.Web.Mvc;
using Keepo.Helpers;
// using KeepoMVC.Controllers;
using System.Diagnostics;
using System.IO;
using Infrastructure.Data;
using Keepo.Helpers;

namespace Keepo.Models.Services
{
    public class DesignTemplatesLogic
    {

        public DesignTemplatesLogic()
        {

        }

        // Set IsRendered to ture
        public void TemplatedRenderFinish(int templateId)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                var template = repository.First<DesignTemplate>(m => m.DesignTemplateId == templateId);
                if (template != null)
                {
                    template.IsRendered = true;
                }

                repository.UnitOfWork.SaveChanges();
            }
        }

        public void SaveToServer(byte[] data, String fileName)
        {
            FileStream fs = File.Create(HttpContext.Current.Server.MapPath("~/") + fileName);
            fs.Write(data, 0, data.Length);
            fs.Close();
        }


        static public void Render(int designTemplateId)
        {
            var req = HttpContext.Current.Request;
            var serverUrl = req.Url.AbsoluteUri.Substring(0, req.Url.AbsoluteUri.LastIndexOf('/'));

            Process myProcess = new Process();
            myProcess.StartInfo.FileName = @"C:\Keepo\Chrome.bat";

            myProcess.StartInfo.Arguments = '"' + "http://localhost:5714/Designer?designerAction=Designer.Render&initProductSelection=false&designableProductId=-1&designTemplateId=" + designTemplateId + '"';
            myProcess.EnableRaisingEvents = false;
            myProcess.Start();
        }

        static public Dictionary<string, int> DesignableProductDetailsById(int designableProductId)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                Dictionary<string, int> dic = new Dictionary<string, int>();

                DesignableProduct designableProduct = repository.First<DesignableProduct>(m => m.DesignableProductId == designableProductId);

                if (designableProduct == null)
                {
                    return null;
                }

                // 260711 TBD
                SubProduct subProduct = repository.First<SubProduct>(m => m.ViewProductId == designableProduct.ViewProductId);

                if (subProduct != null)
                {
                    dic["colorId"] = subProduct.ProductColorId;
                    dic["sizeId"] = subProduct.ProductSizeId;
                }
                else
                {
                    return null;
                }

                return dic;
            }
        }

        static public int SubProductByDetails(int productId, int productColorId)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                //get the SubProduct according to the selected Product,Size and Color
                var subProduct = repository.First<SubProduct>(m => m.ProductId == productId && m.ProductColorId == productColorId);

                return subProduct == null ? -1 : subProduct.SubProductId;
            }
        }

        static public DesignableProductExport DesignableProductBySubProduct(int subProductId)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                var subProduct = repository.First<SubProduct>(m => m.SubProductId == subProductId);

                if (subProduct == null)
                {
                    return null;
                }

                var designableProduct = repository.First<DesignableProduct>(m => m.ViewProductId == subProduct.ViewProduct.ViewProductId);

                if (designableProduct != null)
                {
                    return new DesignableProductExport(designableProduct, subProductId);
                }

                return null;
            }
        }

        static public DesignableProductExport DesignableProductByDetails(int productId, int productColorId)
        {
            int subProductId = SubProductByDetails(productId, productColorId);

            if (subProductId == -1)
            {
                return null;
            }

            return DesignableProductBySubProduct(subProductId);
        }

        static public Dictionary<string, object>[] ProductColorsByProductId(int productId)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                Dictionary<string, object>[] array;
                int idx = 0;

                var subProductsList = repository.Find<SubProduct>(m => m.ProductId == productId);

                var colors = (from subProducts in subProductsList
                              select subProducts.ProductColor).Distinct();

                array = new Dictionary<string, object>[colors.Count()];

                foreach (var color in colors)
                {
                    Dictionary<string, object> dic = new Dictionary<string, object>();

                    dic["key"] = color.ProductColorId;
                    dic["english"] = color.Title;
                    dic["hebrew"] = color.TitleHebrew;
                    dic["RGBHex"] = "#" + color.RGB.ToString("X6");

                    array[idx] = dic;

                    idx++;
                }

                return array;
            }
        }

        static public SelectListItem[] ProductSizesByProductId(int productId, int productColorId)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                var subProductsList = repository.Find<SubProduct>(m => m.ProductId == productId && m.ProductColorId == productColorId);

                var sizes = (from subProducts in subProductsList
                             select subProducts.ProductSize).Distinct().ToArray();

                var sizesSelect = sizes.Select(size => new SelectListItem()
                {
                    Value = size.ProductSizeId.ToString(),
                    Text = size.Title
                });

                return sizesSelect.ToArray();
            }
        }


        static public Template2ProductMap Template2ProductByDesignPageId(int templatePageId, int designPageId)
        {
            return RenderHelper.Template2ProductByDesignPageId(templatePageId, designPageId);
        }

        static public Template2ProductMap Template2Product(int templateId, int templatePageIdx,
            int designableProductId, int productPageIdx)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                DesignableProduct product = repository.GetByKey<DesignableProduct>(designableProductId);
                DesignPage designPage = product == null ? null : product.DesignPages.FirstOrDefault(p => p.ProductPage.PageIdx == productPageIdx && p.ProductPage.IsPrimary);
                int designPageId = designPage == null ? -1 : designPage.DesignPageId;

                DesignTemplate template = repository.GetByKey<DesignTemplate>(templateId);
                TemplatePage templatePage = template == null ? null : template.TemplatePages.FirstOrDefault(p => p.PageIdx == templatePageIdx);
                int templatePageId = templatePage == null ? -1 : templatePage.TemplatePageId;

                return Template2ProductByDesignPageId(templatePageId, designPageId);
            }
        }

        static public ImageMap getProductImageMapping2(int designableProductId, int productPageIdx,
            int canvasWidth, int canvasHeight)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                DesignableProduct product = repository.GetByKey<DesignableProduct>(designableProductId);
                DesignPage designPage = product.DesignPages.FirstOrDefault(p => p.ProductPage.PageIdx == productPageIdx);
                ProductPage productPage = designPage.ProductPage;
                PrinterPage printerPage = product.PrinterPages.FirstOrDefault(p => p.PageIdx == productPageIdx);

                // Missing Data
                if (designPage == null || productPage == null || productPage.DesignImage == null)
                {
                    return new ImageMap();
                }

                PrintSize printSize = printerPage.PrintSize;
                
                ImageMap map = new ImageMap();
                float productImageDPI = (float)designPage.DesignImageDPI;

                // Calculate display's DPI // Verify ByWidth =~ ByHeight?
                float displayDpiByWidth = canvasWidth / printSize.WebsiteWidthInch;
                float displayDpiByHeight = canvasHeight / printSize.WebsiteHeightInch;
                float displayDpi = Math.Max(displayDpiByWidth, displayDpiByHeight);
                
                // Scale image to display's DPI
                map.Scale = displayDpi / productImageDPI;

                // Center of WPA in native DPI
                map.OffsetX = -(designPage.ImageOffsetXInch + (printSize.WebsiteOffsetXInch ?? 0) + printSize.WebsiteWidthInch / 2) * displayDpi;
                map.OffsetY = -(designPage.ImageOffsetYInch + (printSize.WebsiteOffsetYInch ?? 0) + printSize.WebsiteHeightInch / 2) * displayDpi;

                map.URL = productPage.DesignImage.URL;

                return map;
            }
        }

        /*static public ImageMap getProductImageMapping(int designableProductId, int productPageIdx,
            int templateId, int templatePageIdx)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                DesignableProduct product = repository.GetByKey<DesignableProduct>(designableProductId);
                DesignPage designPage = product.DesignPages.FirstOrDefault(p => p.ProductPage.PageIdx == productPageIdx);
                ProductPage productPage = designPage.ProductPage;
                PrinterPage printerPage = product.PrinterPages.FirstOrDefault(p => p.PageIdx == productPageIdx);

                DesignTemplate template = repository.GetByKey<DesignTemplate>(templateId);
                TemplatePage templatePage = template.TemplatePages.FirstOrDefault(p => p.PageIdx == templatePageIdx);

                // Missing Data
                if (templatePage == null || designPage == null || productPage == null || productPage.DesignImage == null)
                {
                    return new ImageMap();
                }

                PrintSize printSize = printerPage.PrintSize;

                Rect fittedRect = PrintHelper.fitRect(printSize.WebsiteWidthInch, printSize.WebsiteHeightInch,
                    templatePage.TemplateWidthPix, templatePage.TemplateHeightPix);

                float viewportDPI = templatePage.XmlWidthPix / fittedRect.Width;

                ImageMap map = new ImageMap();

                map.OffsetX = -(designPage.ImageOffsetXInch + fittedRect.OffsetX + (printSize.WebsiteOffsetXInch ?? 0)) * viewportDPI;
                map.OffsetY = -(designPage.ImageOffsetYInch + fittedRect.OffsetY + (printSize.WebsiteOffsetYInch ?? 0)) * viewportDPI;

                map.URL = productPage.DesignImage.URL;
                map.Scale = viewportDPI / (float)designPage.DesignImageDPI;

                return map;
            }
        }*/

        static public Rect getTpaMapping2(int designableProductId, int productPageIdx,
            int canvasWidth, int canvasHeight)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                DesignableProduct product = repository.GetByKey<DesignableProduct>(designableProductId);
                DesignPage designPage = product.DesignPages.FirstOrDefault(p => p.ProductPage.PageIdx == productPageIdx);
                PrinterPage printerPage = product.PrinterPages.FirstOrDefault(p => p.PageIdx == productPageIdx);
                PrintSize printSize = printerPage.PrintSize;
                PrintTable printTable = printSize.PrintTable;

                if (designPage == null || printTable == null)
                {
                    return new Rect();
                }

                float s1 = canvasWidth / printSize.WebsiteWidthInch;
                float s2 = canvasHeight / printSize.WebsiteHeightInch;

                float scale = Math.Max(s1, s2);

                Rect rect = new Rect();
                rect.Width = printTable.TableWidthInch * scale;
                rect.Height = printTable.TableHeightInch * scale;
                rect.OffsetX = -((printSize.WebsiteWidthInch / 2) + (printSize.WebsiteOffsetXInch ?? 0)) * scale;
                rect.OffsetY = -((printSize.WebsiteHeightInch / 2) + (printSize.WebsiteOffsetYInch ?? 0)) * scale;

                return rect;
            }
        }

        /*static public Rect getTpaMapping(int designableProductId, int productPageIdx,
            int templateId, int templatePageIdx)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                DesignableProduct product = repository.GetByKey<DesignableProduct>(designableProductId);
                DesignPage designPage = product.DesignPages.FirstOrDefault(p => p.ProductPage.PageIdx == productPageIdx);
                PrinterPage printerPage = product.PrinterPages.FirstOrDefault(p => p.PageIdx == productPageIdx);

                DesignTemplate template = repository.GetByKey<DesignTemplate>(templateId);
                TemplatePage templatePage = template.TemplatePages.FirstOrDefault(p => p.PageIdx == templatePageIdx);

                if (designPage == null)
                {
                    return new Rect();
                }

                PrintSize printSize = printerPage.PrintSize;

                Rect fittedRect = PrintHelper.fitRect(printSize.WebsiteWidthInch, printSize.WebsiteHeightInch,
                    templatePage.TemplateWidthPix, templatePage.TemplateHeightPix);

                float viewportDPI = templatePage.XmlWidthPix / fittedRect.Width;

                Rect tpa = new Rect();
                tpa.Width = printSize.PrintTable.TableWidthInch * viewportDPI;
                tpa.Height = printSize.PrintTable.TableHeightInch * viewportDPI;

                tpa.OffsetX = -(fittedRect.OffsetX + (printSize.WebsiteOffsetXInch ?? 0)) * viewportDPI;
                tpa.OffsetY = -(fittedRect.OffsetY + (printSize.WebsiteOffsetYInch ?? 0)) * viewportDPI;

                return tpa;
            }
        }*/

        static public Rect getWpaMapping2(int designableProductId, int productPageIdx,
            int canvasWidth, int canvasHeight)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                DesignableProduct product = repository.GetByKey<DesignableProduct>(designableProductId);
                DesignPage designPage = product.DesignPages.FirstOrDefault(p => p.ProductPage.PageIdx == productPageIdx);
                PrinterPage printerPage = product.PrinterPages.FirstOrDefault(p => p.PageIdx == productPageIdx);

                if (designPage == null || printerPage == null)
                {
                    return new Rect();
                }

                PrintSize printSize = printerPage.PrintSize;

                float s1 = canvasWidth / printSize.WebsiteWidthInch;
                float s2 = canvasHeight / printSize.WebsiteHeightInch;

                float scale = Math.Max(s1, s2);

                Rect rect = new Rect();
                rect.Width = printSize.WebsiteWidthInch * scale;
                rect.Height = printSize.WebsiteHeightInch * scale;
                rect.OffsetX = -rect.Width / 2;
                rect.OffsetY = -rect.Height / 2;

                return rect;
            }
        }

        /*static public Rect getWpaMapping(int designableProductId, int productPageIdx,
            int templateId, int templatePageIdx)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                DesignableProduct product = repository.GetByKey<DesignableProduct>(designableProductId);
                DesignPage designPage = product.DesignPages.FirstOrDefault(p => p.ProductPage.PageIdx == productPageIdx);
                PrinterPage printerPage = product.PrinterPages.FirstOrDefault(p => p.PageIdx == productPageIdx);

                DesignTemplate template = repository.GetByKey<DesignTemplate>(templateId);
                TemplatePage templatePage = template.TemplatePages.FirstOrDefault(p => p.PageIdx == templatePageIdx);

                if (designPage == null)
                {
                    return new Rect();
                }

                PrintSize printSize = printerPage.PrintSize;

                Rect fittedRect = PrintHelper.fitRect(printSize.WebsiteWidthInch, printSize.WebsiteHeightInch,
                    templatePage.TemplateWidthPix, templatePage.TemplateHeightPix);

                float viewportDPI = templatePage.XmlWidthPix / fittedRect.Width;

                Rect wpa = new Rect();
                wpa.Width = printSize.WebsiteWidthInch * viewportDPI;
                wpa.Height = printSize.WebsiteHeightInch * viewportDPI;
                wpa.OffsetX = -fittedRect.OffsetX * viewportDPI;
                wpa.OffsetY = -fittedRect.OffsetY * viewportDPI;

                return wpa;
            }
        }*/

        static public Dictionary<string, object>[] getAllProducts()
        {
            using (GenericRepository repository = new GenericRepository())
            {
                Dictionary<string, object>[] array;
                int idx = 0;

                var products = repository.GetAll<Product>();

                array = new Dictionary<string, object>[products.Count()];

                foreach (var product in products)
                {
                    Dictionary<string, object> dic = new Dictionary<string, object>();

                    dic["key"] = product.ProductId;
                    dic["english"] = product.Title;
                    dic["hebrew"] = product.TitleHebrew;

                    array[idx] = dic;

                    idx++;
                }

                return array;
            }
        }


        static public Dictionary<string, object>[] getTemplateCategories()
        {
            using (GenericRepository repository = new GenericRepository())
            {
                Dictionary<string, object>[] array;
                int idx = 0;

                var categories = repository.GetAll<TemplateCategory>();

                array = new Dictionary<string, object>[categories.Count()];

                foreach (var cat in categories)
                {
                    Dictionary<string, object> dic = new Dictionary<string, object>();

                    dic["key"] = cat.TemplateCategoryId;
                    dic["english"] = cat.Title;
                    dic["hebrew"] = cat.TitleHebrew;

                    array[idx] = dic;

                    idx++;
                }

                return array;
            }
        }

        static public DesignTemplateExport[] getTemplatesByCategoryId(int categoryId, string orderBy = "None")
        {
            return TemplateHelper.getTemplatesByCategoryId(categoryId, orderBy);
        }

        static public DesignTemplateExport[] getTemplatesByBackgroundRgb(int backgroundRgb, string orderBy = "None")
        {
            return TemplateHelper.getTemplatesByBackgroundRgb(backgroundRgb, orderBy);
        }

        static public DesignTemplateExport[] getTemplatesByKeyword(string keyword, string orderBy = "None")
        {
            return TemplateHelper.getTemplatesByKeyword(keyword, orderBy);
        }

        static public DesignTemplateExport[] getTemplatesByHot(string orderBy = "None")
        {
            return TemplateHelper.getTemplatesByHot(orderBy);
        }

        static public DesignTemplateExport getTemplateById(int templateId)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                DesignTemplate template = repository.GetByKey<DesignTemplate>(templateId);

                if (template == null)
                {
                    return null;
                }

                return new DesignTemplateExport(template);
            }
        }
        
        // Create new Template and return ID
        static public int createDesignTemplate(DesignTemplateExport template)
        {
            int templateId = TemplateHelper.createDesignTemplate(template);
            return templateId;
        }

        static public DesignTemplateExport[] getAllTemplates()
        {
            using (GenericRepository repository = new GenericRepository())
            {
                var templates = repository.GetAll<DesignTemplate>();

                var exportTemplates = templates.ToArray().Select(template => new DesignTemplateExport(template));

                return exportTemplates.ToArray();
            }
        }

        static public PointExport[] getWpaSizeByDesignableProductId(int designableProductId)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                List<PointExport> sizes = new List<PointExport>();

                DesignableProduct product = repository.GetByKey<DesignableProduct>(designableProductId);

                if (product == null)
                {
                    return null;
                }

                
                foreach( var designPage in product.DesignPages.OrderBy( p => p.ProductPage.PageIdx) )
                {
                    PointExport point = new PointExport();

                    point.idx = designPage.ProductPage.PageIdx;

                    PrinterPage printerPage = product.PrinterPages.FirstOrDefault(p => p.PageIdx == point.idx);

                    point.x = printerPage.PrintSize.WebsiteWidthInch;
                    point.y = printerPage.PrintSize.WebsiteHeightInch;

                    sizes.Add(point);
                }

                return sizes.ToArray();
            }
        }

        static public Rect[] getBleedSizeByDesignableProductId(int designableProductId)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                List<Rect> bleeds = new List<Rect>();

                DesignableProduct product = repository.GetByKey<DesignableProduct>(designableProductId);

                if (product == null)
                {
                    return null;
                }

                foreach( var designPage in product.DesignPages.OrderBy( p => p.ProductPage.PageIdx) )
                {
                    Rect rect = new Rect() { Idx = designPage.ProductPage.PageIdx };

                    PrinterPage printerPage = product.PrinterPages.FirstOrDefault(p => p.PageIdx == rect.Idx);

                    rect.OffsetX = printerPage.PrintSize.BleedOffsetXInch ?? 0;
                    rect.OffsetY = printerPage.PrintSize.BleedOffsetYInch ?? 0;
                    rect.Width = printerPage.PrintSize.BleedWidthInch ?? 0;
                    rect.Height = printerPage.PrintSize.BleedHeightInch ?? 0;

                    bleeds.Add(rect);
                }

                return bleeds.ToArray();
            }
        }


        static public bool IsPrintSizeEqual(int designProductId1, int designProductId2)
        {
            using (GenericRepository repository = new GenericRepository())
            {
                var designProduct1 = repository.GetByKey<DesignableProduct>(designProductId1);
                var designProduct2 = repository.GetByKey<DesignableProduct>(designProductId2);

                if (designProduct1 == null || designProduct2 == null)
                {
                    return false;
                }

                if (designProduct1.PrinterPages.Count() != designProduct2.PrinterPages.Count())
                {
                    return false;
                }

                int numPages = designProduct1.PrinterPages.Count();

                for (int idx = 0; idx < numPages; idx++)
                {
                    var page1 = designProduct1.PrinterPages.FirstOrDefault(p => p.PageIdx == idx);
                    var page2 = designProduct2.PrinterPages.FirstOrDefault(p => p.PageIdx == idx);

                    if (page1 == null || page2 == null)
                    {
                        return false;
                    }

                    if (page1.PrintSize.PrintSizeId != page2.PrintSize.PrintSizeId)
                    {
                        return false;
                    }
                }

                return true;
            }
        }

        static public bool Login(String email, String password, bool rememberMe)
        {
            LoginData data = new LoginData() { Email = email, Password = password, RememberMe = rememberMe };
            HttpResponseWrapper response = new HttpResponseWrapper(HttpContext.Current.Response);
            HttpSessionStateWrapper session = new HttpSessionStateWrapper(HttpContext.Current.Session);
            var result = UserHelper.Login(data, response, session);
            return result.Key;
        }

        static public bool LoginWithUserId(int userId)
        {
            HttpResponseWrapper response = new HttpResponseWrapper(HttpContext.Current.Response);
            HttpSessionStateWrapper session = new HttpSessionStateWrapper(HttpContext.Current.Session);
            var result = UserHelper.Login(userId, response, session);
            return result.Key;
        }


        static public KeyValue RegisterUser(RegisterDataExport registerDataExport)
        {
            // Check non empty
            if (registerDataExport.RegistrationCode == "" ||
                registerDataExport.FirstName == "" ||
                registerDataExport.LastName == "" ||
                registerDataExport.Email == "" ||
                registerDataExport.Cellular == "")
            {
                return new KeyValue() { Key = 0, Value = "All * Fields are required" };
            }

            // Check if Registration code is valid
            string registrationCode = registerDataExport.RegistrationCode;

            var result = UserHelper.isRegistrationCodeValid(registerDataExport.RegistrationCode);

            if (result.Key == false)
            {
                return new KeyValue() { Key = Convert.ToInt32(result.Key), Value = result.Value };
            }

            if (UserHelper.IsEmailRegisteredToUser(registerDataExport.Email))
            {
                return new KeyValue() { Key = 0, Value = "Email is registered to another user" };
            }

            // RegisterDataExport => RegisterData
            RegisterData registerData = new RegisterData()
            {
                Email = registerDataExport.Email,
                Password = registerDataExport.Password,
                ConfirmedPassword = registerDataExport.ConfirmPassword,
                FirstName = registerDataExport.FirstName,
                LastName = registerDataExport.LastName
            };

            // Register the user
            int userId = UserHelper.Register(registerData);

            UserHelper.InvalidateRegistrationCode(registerDataExport.RegistrationCode, userId);

            // Add user info
            UserInfo userInfo = new UserInfo()
            {

                Cellular = registerDataExport.Cellular,
                Department = registerDataExport.Department,
                Manager = registerDataExport.Manager,
                Phone = registerDataExport.Phone,
                UserId = userId
            };

            UserHelper.addUserInfo(userInfo);

            UserHelper.ActivateUser(userId);

            LoginWithUserId(userId);

            return new KeyValue() { Key = 1, Value = registerDataExport.Email };
        }

    }
}